//---------------------------------------------------------------------------------
// Copyright (c) 2008 VoiceLynx Project
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
//     1. The origin of this software must not be misrepresented; you must not
//        claim that you wrote the original software. If you use this software
//        in a product, an acknowledgment in the product documentation would be
//        appreciated but is not required.
//
//     2. Altered source versions must be plainly marked as such, and must not be
//        misrepresented as being the original software.
//
//     3. This notice may not be removed or altered from any source
//        distribution.
//---------------------------------------------------------------------------------

#ifndef __VLPackets_h__
#define __VLPackets_h__

#include <deque>
#include "VLPrerequisites.h"
#include "VLDataStream.h"
#include "VLUser.h"
#include "VLChannel.h"
#include "VLTypes.h"

typedef void* VLHostId;

extern const char *VL_PACKET_TYPE_DS_NAME;

struct VLRawIncomingPacket
{
  VLHostId fromHostId;
  VLByteArrayPtr data;
};

typedef std::auto_ptr<VLRawIncomingPacket> VLRawIncomingPacketPtr;

struct VLRawOutgoingPacket
{
  VLHostId destHostId;
  VLByteArrayPtr data;
};

typedef std::auto_ptr<VLRawOutgoingPacket> VLRawOutgoingPacketPtr;
typedef std::deque<VLRawOutgoingPacket *>  VLRawOutgoingPackets;

enum VLEPacketType
{
  VL_PT_UNKNOWN,                    // should never be used        
  VL_PT_STARTVOICE,                 // sent by client to server, then server to all peers
  VL_PT_VOICEDATA,                  // a "frame" of voice data
  VL_PT_STOPVOICE,                  // see VL_PT_STOPVOICE
  VL_PT_AUTHENTICATION,             // Attempt to "log in" using username/password
  VL_PT_AUTHENTICATION_RESPONSE,    // sent from server to client if auth successful
  VL_PT_USER_JOINED,                // sent from server to all clients but joiner
  VL_PT_USER_CHANGED_CHANNEL,       // sent from server to all clients (including changer)
  VL_PT_USER_LEFT,                  // sent from server to all clients but leaver
  VL_PT_CHANNEL_STATE_REQUEST,      // sent from client to server to ask for a channel_state packet
  VL_PT_CHANNEL_STATE,              // sent from server to client
  VL_PT_END                         // not a packet type - "custom" packet type IDs must be
                                    // greater than this value
};

class VLBasePacket
{
public:

  VLBasePacket(VLEPacketType packetType);
  VLBasePacket(InDataStream &ds);

  virtual void serialize(OutDataStream &ds);

  VLEPacketType getPacketType() { return mPacketType; }

  virtual ~VLBasePacket() { }

private:
  VLEPacketType mPacketType;
};

class VLAuthenticationPacket : public VLBasePacket
{
public:
  VLAuthenticationPacket(const VLString &name, const VLString &password);
  VLAuthenticationPacket(InDataStream &ds);

  virtual void serialize(OutDataStream &ds);

  VLString name;
  VLString password;
};

class VLAuthenticationResponsePacket : public VLBasePacket
{
public:
  VLAuthenticationResponsePacket(bool successful, VLUserId userId);
  VLAuthenticationResponsePacket(InDataStream &ds);

  virtual void serialize(OutDataStream &ds);

  bool successful;
  int userId;
};

class VLChannelStateRequestPacket : public VLBasePacket
{
public:
  VLChannelStateRequestPacket() : VLBasePacket(VL_PT_CHANNEL_STATE_REQUEST) { }
  VLChannelStateRequestPacket(InDataStream &ds) : VLBasePacket(ds) { }
};

class VLChannelStatePacket : public VLBasePacket
{
public:
  VLChannelStatePacket() : VLBasePacket(VL_PT_CHANNEL_STATE) { }
  VLChannelStatePacket(InDataStream &ds) : VLBasePacket(ds) { }
};

class VLUserPacket : public VLBasePacket
{
public:
  VLUserPacket(VLEPacketType packetType, VLUserId userId);
  VLUserPacket(InDataStream &ds);

  virtual void serialize(OutDataStream &ds);

  VLUserId userId;
};

class VLUserJoinedPacket : public VLUserPacket
{
public:
  VLUserJoinedPacket(VLUser &user);
  VLUserJoinedPacket(InDataStream &ds);

  virtual void serialize(OutDataStream &ds);

  void applyToUser(VLUser &user);

  VLString userName;
  bool     isAuthenticated;
  VLU32    connectTime;
};

class VLUserLeftPacket : public VLUserPacket
{
public:
  VLUserLeftPacket(VLUserId userId);
  VLUserLeftPacket(InDataStream &ds);

  virtual void serialize(OutDataStream &ds);
};

class VLUserChangedChannelPacket : public VLUserPacket
{
public:
  VLUserChangedChannelPacket(VLUserId userId);
  VLUserChangedChannelPacket(InDataStream &ds);

  virtual void serialize(OutDataStream &ds);
};

class VLVoiceDataPacket : public VLUserPacket
{
public:
  VLVoiceDataPacket(VLUserId userId, VLU8 codecChannelHash, VLByteArrayPtr voiceData);
  VLVoiceDataPacket(InDataStream &ds);

  virtual void serialize(OutDataStream &ds);

  VLU8 getCodecChannelHash() { return mCodecChannelHash; }
  VLByteArrayPtr &getVoiceData() { return mVoiceData; }

private:
  VL32           mCodecChannelHash;
  VLByteArrayPtr mVoiceData;
};

class VLStartVoicePacket : public VLUserPacket
{
public:
  VLStartVoicePacket(VLUserId userId) : VLUserPacket(VL_PT_STARTVOICE, userId) { }
  VLStartVoicePacket(InDataStream &ds) : VLUserPacket(ds) { }
};

class VLStopVoicePacket : public VLUserPacket
{
public:
  VLStopVoicePacket(VLUserId userId) : VLUserPacket(VL_PT_STOPVOICE, userId) { }
  VLStopVoicePacket(InDataStream &ds) : VLUserPacket(ds) { }
};

typedef std::auto_ptr<VLBasePacket> VLPacketPtr;

#endif
